•迪杰斯特拉(Dijkstra)算法思想
按路径长度递增次序产生最短路径算法:
把V分成两组:
(1)S:已求出最短路径的顶点的集合
(2)V-S=T:尚未确定最短路径的顶点集合
将T中顶点按最短路径递增的次序加入到S中,
保证:(1)从源点V0到S中各顶点的最短路径长度都不大于
从V0到T中任何顶点的最短路径长度
(2)每个顶点对应一个距离值
S中顶点:从V0到此顶点的最短路径长度
T中顶点:从V0到此顶点的只包括S中顶点作中间
顶点的最短路径长度
依据:可以证明V0到T中顶点Vk的最短路径,或是从V0到Vk的
直接路径的权值;或是从V0经S中顶点到Vk的路径权值之和
(反证法可证)
•
求最短路径步骤
–
初使时令
S={V0},T={
其余顶点},
T
中顶点对应的距离值
»
若存在
<V0,Vi>
,为
<V0,Vi>
弧上的权值
»
若不存在<
V0,Vi>
,
为
µ
–
从
T
中选取一个其距离值为最小的顶点
W
,加入
S
–
对
T
中顶点的距离值进行修改:若加进
W
作中间顶点,从
V0
到
Vi
的距离值比不加
W
的路径要短,则修改此距离值
–
重复上述步骤,直到
S
中包含所有顶点,即
S=V
为止
•算法实现
–图用带权邻接矩阵存储ad[][]
–数组dist[]存放当前找到的从源点V0到每个终点的最短路径长度,其初态为图中直接路径权值
–数组pre[]表示从V0到各终点的最短路径上,此顶点的前一顶点的序号;若从V0到某终点无路径,则用0作为其前一顶点的序号
§每一对顶点之间的最短路径
•方法一:每次以一个顶点为源点,重复执行Dijkstra算法n次—— T(n)=O(n³)
•方法二:弗洛伊德(Floyd)算法
–算法思想:逐个顶点试探法
–求最短路径步骤
»初始时设置一个n阶方阵,令其对角线元素为0,若存在弧<Vi,Vj>,则对应元素为权值;否则为µ
»逐步试着在原直接路径中增加中间顶点,若加入中间点后路径变短,则修改之;否则,维持原值
»所有顶点试探完毕,算法结束
代码实现:
/*Dijkstra求单源最短路径 */
#include <iostream>
#include<stdlib.h>
#include<stack>
#define M 100
#define N 100
using namespace std;
typedef struct node
{
int matrix[N][M]; //邻接矩阵
int n; //顶点数
int e; //边数
}MGraph;
void DijkstraPath(MGraph g,int *dist,int *path,int v0) //v0表示源顶点
{
int i,j,k;
bool *visited=(bool *)malloc(sizeof(bool)*g.n);
for(i=0;i<g.n;i++) //初始化
{
if(g.matrix[v0][i]>0&&i!=v0)
{
dist[i]=g.matrix[v0][i];
path[i]=v0; //path记录最短路径上从v0到i的前一个顶点
}
else
{
dist[i]=INT_MAX; //若i不与v0直接相邻,则权值置为无穷大
path[i]=-1;
}
visited[i]=false;
path[v0]=v0;
dist[v0]=0;
}
visited[v0]=true;
for(i=1;i<g.n;i++) //循环扩展n-1次
{
int min=INT_MAX;
int u;
for(j=0;j<g.n;j++) //寻找未被扩展的权值最小的顶点
{
if(visited[j]==false&&dist[j]<min)
{
min=dist[j];
u=j;
}
}
visited[u]=true;
for(k=0;k<g.n;k++) //更新dist数组的值和路径的值
{
if(visited[k]==false&&g.matrix[u][k]>0&&min+g.matrix[u][k]<dist[k])
{
dist[k]=min+g.matrix[u][k];
path[k]=u;
}
}
}
}
void showPath(int *path,int v,int v0) //打印最短路径上的各个顶点
{
stack<int> s;
int u=v;
while(v!=v0)
{
s.push(v);
v=path[v];
}
s.push(v);
while(!s.empty())
{
cout<<s.top()<<" ";
s.pop();
}
}
int main(int argc, char *argv[])
{
int n,e; //表示输入的顶点数和边数
while(cin>>n>>e&&e!=0)
{
int i,j;
int s,t,w; //表示存在一条边s->t,权值为w
MGraph g;
int v0;
int *dist=(int *)malloc(sizeof(int)*n);
int *path=(int *)malloc(sizeof(int)*n);
for(i=0;i<N;i++)
for(j=0;j<M;j++){
g.matrix[i][j]=0;
g.n=n;
g.e=e;
}
for(i=0;i<e;i++)
{
cin>>s>>t>>w;
g.matrix[s][t]=w;
}
cin>>v0; //输入源顶点
DijkstraPath(g,dist,path,v0);
for(i=0;i<n;i++)
{
if(i!=v0)
{
showPath(path,i,v0);
cout<<dist[i]<<endl;
}
}
}
system("pause");
return 0;
}
另一种写法:
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#define INF 0x3f3f3f3f
using namespace std;
const int MAX = 105;
int n,m;//n个点,m条边;
int st,en;//存起点和终点
vector<int >edge[MAX]; //存与之相连的点
int length [MAX][MAX];//存边的长度
int dis[MAX];
bool vis[MAX];
struct Node{
int point,distance;
bool friend operator <(Node a,Node b){
return a.distance > b.distance;
}
}pr,np;
void dijkstra(){
memset(dis,INF,sizeof(dis));
memset(vis,false,sizeof(vis));
dis[st]=0;
priority_queue<Node> Q;
pr.point=st;
pr.distance=0;
Q.push(pr);
while(!Q.empty()){
pr=Q.top();
Q.pop();
// cout<<"==="<<pr.point<<endl;
if(vis[pr.point]||pr.point==en)
continue;
vis[pr.point]=true;
for(int i=0;i<edge[pr.point].size();i++){
np.point=edge[pr.point][i];
np.distance=pr.distance+length[pr.point][np.point];
if(np.distance < dis[np.point]){
dis[np.point]=np.distance;
Q.push(np);
}
}
}
}
int main(){
while(cin>>n>>m&&(n||m)){
st=1;
en=n;
memset(length,INF,sizeof(length));
for(int i=0;i<m;i++){
int x,y,z;
cin>>x>>y>>z;
edge[x].push_back(y);//存双向边
edge[y].push_back(x);
if(length[x][y]>z)
length[x][y]=length[y][x]=z;
}
dijkstra();
cout<<dis[en]<<endl;
}
return 0;
}